"""调度器服务的Celery任务模块
提供任务调度的异步处理功能
"""
import json
import os
import traceback
from datetime import datetime

from services.shared.celery_app import celery_app
from services.shared.database import Task, TaskExecution
from services.shared.db_pool import get_db_session, close_db_session
from services.shared.logger import get_logger
from services.shared.models import TaskStatus
from services.shared.timezone_utils import now as timezone_now
from services.shared.log_utils import log_error, log_info, log_system_event, log_task_operation
from services.shared.utils import generate_execution_id

# 获取日志记录器
logger = get_logger('scheduler.tasks')

# 初始化WebSocket服务URL（用于celery worker）
def _init_websocket_service():
    """初始化WebSocket服务URL"""
    try:
        from services.shared.websocket_service import get_websocket_service
        from config.config import get_config
        
        websocket_service = get_websocket_service()
        # 在Docker环境中使用容器名，否则使用localhost
        if os.environ.get('SERVICE_TYPE') == 'celery-workers':
            config = get_config()
            web_service_url = f"http://xbyjob-app-services:{config.WEB_SERVICE_PORT}"
            websocket_service.set_web_service_url(web_service_url)
            logger.info(f"WebSocket服务URL设置为: {web_service_url}")
    except Exception as e:
        logger.warning(f"初始化WebSocket服务失败: {str(e)}")

# 在模块加载时初始化WebSocket服务
_init_websocket_service()


@celery_app.task(name='schedule_task')
def schedule_task(task_id, params=None):
    """调度任务执行
    
    Args:
        task_id: 任务ID
        params: 任务参数，覆盖任务默认参数
    
    Returns:
        调度结果字典
    """
    logger.debug(f"开始调度任务: {task_id}, 参数: {params}")
    logger.info(f"调度任务: {task_id}, 参数: {params}")
    
    try:
        # 获取任务信息
        logger.debug(f"获取数据库会话准备查询任务: {task_id}")
        session = get_db_session()
        try:
            logger.debug(f"查询任务信息: {task_id}")
            task = session.query(Task).get(task_id)
            
            if not task:
                error_msg = f"任务不存在: {task_id}"
                logger.error(error_msg)
                logger.debug(f"任务查询结果为空: {task_id}")
                return {'success': False, 'error': error_msg}
            
            # 检查任务是否启用
            logger.debug(f"检查任务状态: {task_id}, 当前状态: {task.status}, 是否启用: {task.is_enabled}")
            if not task.is_enabled:
                error_msg = f"任务未启用: {task_id}, is_enabled: {task.is_enabled}"
                logger.warning(error_msg)
                logger.debug(f"任务启用状态检查失败: {task_id}, is_enabled: {task.is_enabled}")
                return {'success': False, 'error': error_msg}
            
            # 移除并发限制检查，任务直接进入队列由执行器处理
            logger.debug(f"准备调度任务到执行队列: {task_id}")
            
            # 创建执行记录
            logger.debug(f"创建任务执行记录: {task_id}")
            current_time = timezone_now()
            # 使用UUID确保execution_id唯一性，与手动执行保持一致
            execution_id = generate_execution_id()
            logger.debug(f"生成执行ID: {execution_id}, 时间戳: {current_time}")
            
            execution = TaskExecution(
                task_id=task_id,
                status=TaskStatus.PENDING,
                execution_id=execution_id
                # 不在这里设置started_at，而是在任务真正开始执行时设置
            )
            logger.debug(f"添加执行记录到会话: {execution.to_dict() if hasattr(execution, 'to_dict') else execution}")
            session.add(execution)
            logger.debug(f"提交执行记录到数据库")
            session.commit()
            execution_id = execution.execution_id
            logger.debug(f"执行记录创建成功，ID: {execution_id}")
            
            # 调用执行器任务
            logger.debug(f"导入执行器任务模块")
            from services.executor.tasks import execute_task
            # 构建任务数据字典
            logger.debug(f"构建任务数据字典")
            task_data = {
                'task_id': task_id,
                'execution_id': execution_id,
                'params': params
            }
            logger.debug(f"任务数据: {task_data}")
            # 使用关键字参数调用
            logger.debug(f"调用执行器任务: execute_task.delay(task_data={task_data})")
            result = execute_task.delay(task_data=task_data)
            logger.debug(f"执行器任务调用成功，Celery任务ID: {result.id}")
            
            # 更新执行记录信息
            logger.debug(f"更新执行记录的执行器PID: {os.getpid()}")
            execution.executor_pid = os.getpid()
            logger.debug(f"提交执行记录更新")
            session.commit()
            logger.debug(f"执行记录更新成功")
            
            logger.info(f"任务已调度: {task_id}, 执行ID: {execution_id}, Celery任务ID: {result.id}")
            return_data = {
                'success': True,
                'task_id': task_id,
                'execution_id': execution_id,
                'celery_task_id': result.id
            }
            logger.debug(f"返回调度结果: {return_data}")
            
            # 记录任务调度成功的操作日志
            log_task_operation(
                action='schedule',
                task_id=task_id,
                task_name=f"Task-{task_id}",
                user_id=None,
                execution_time=None,
                status_code=200,
                error_message=None,
                details=f"任务调度成功: {task_id}"
            )
            
            return return_data
        finally:
            logger.debug(f"关闭数据库会话")
            close_db_session()
            logger.debug(f"数据库会话已关闭")
            
    except Exception as e:
        error_msg = f"调度任务失败: {str(e)}"
        logger.error(error_msg)
        logger.debug(f"调度任务异常详情: {traceback.format_exc()}")
        
        # 记录任务调度失败的操作日志
        log_task_operation(
            action='schedule',
            task_id=task_id,
            task_name=f"Task-{task_id}",
            user_id=None,
            execution_time=None,
            status_code=500,
            error_message=str(e),
            details=f"任务调度失败: {str(e)}"
        )
        
        return_data = {'success': False, 'error': error_msg}
        logger.debug(f"返回错误结果: {return_data}")
        return return_data


@celery_app.task(name='check_tasks')
def check_tasks():
    """检查所有任务是否需要触发
    
    Returns:
        检查结果字典
    """
    logger.debug("开始检查所有任务是否需要触发")
    logger.info("检查所有任务是否需要触发")
    
    # 使用Redis分布式锁防止重复执行
    import redis
    from config.config import get_config
    
    config = get_config()
    
    # 获取分布式锁
    import redis
    redis_client = redis.from_url(config.REDIS_URL, decode_responses=True)
    
    lock_key = "check_tasks_lock"
    lock_timeout = 30  # 30秒超时
    
    # 尝试获取锁
    if not redis_client.set(lock_key, "locked", nx=True, ex=lock_timeout):
        logger.info("另一个check_tasks任务正在执行，跳过本次执行")
        return {'success': True, 'result': {'skipped': True, 'reason': 'Another check_tasks is running'}}
    
    try:
        logger.debug("获取到分布式锁，开始执行任务检查")
        logger.debug("导入TaskScheduler类")
        from services.scheduler.scheduler import TaskScheduler
        logger.debug("初始化TaskScheduler实例")
        scheduler = TaskScheduler()
        logger.info("调用_check_cron_tasks方法")
        
        # 检查任务（_check_cron_tasks现在直接从数据库加载任务）
        triggered_count = scheduler._check_cron_tasks()
        
        logger.debug(f"_check_cron_tasks方法返回结果: {triggered_count}")
        
        result = {'triggered_tasks': triggered_count}
        logger.info(f"任务检查完成: {result}")
        return_data = {'success': True, 'result': result}
        logger.debug(f"返回检查结果: {return_data}")
        
        # 记录任务检查成功的信息日志
        log_info(
            "scheduler_check_tasks_success",
            f"任务检查成功完成，触发了{triggered_count}个任务",
            details=json.dumps({
                "result": result,
                "execution_context": {
                    "function": "check_tasks",
                    "module": "scheduler.tasks",
                    "lock_key": "check_tasks_lock"
                }
            }, ensure_ascii=False)
        )
        
        return return_data
    except Exception as e:
        error_msg = f"检查任务失败: {str(e)}"
        logger.error(error_msg)
        logger.debug(f"检查任务异常详情: {traceback.format_exc()}")
        
        # 记录详细的系统错误日志
        log_error(
            "scheduler_check_tasks_failed",
            f"任务检查失败: {str(e)}",
            details=json.dumps({
                "error_type": type(e).__name__,
                "error_message": str(e),
                "traceback": traceback.format_exc(),
                "execution_context": {
                    "function": "check_tasks",
                    "module": "scheduler.tasks",
                    "lock_key": "check_tasks_lock"
                }
            }, ensure_ascii=False)
        )
        
        return_data = {'success': False, 'error': error_msg}
        logger.debug(f"返回错误结果: {return_data}")
        return return_data
    finally:
        # 释放锁
        try:
            redis_client.delete(lock_key)
            logger.debug("释放分布式锁")
        except Exception as e:
            logger.warning(f"释放分布式锁失败: {str(e)}")


@celery_app.task(name='cleanup_recycle_items')
def cleanup_recycle_items(days=30):
    """清理过期的回收站项目
    
    Args:
        days: 保留天数，默认30天
    
    Returns:
        清理结果字典
    """
    logger.debug(f"开始执行清理{days}天前的回收站项目")
    logger.info(f"开始清理{days}天前的回收站项目")
    
    try:
        from datetime import timedelta
        from services.shared.models.recycle import RecycleBin
        from services.shared.database import db
        
        # 计算过期时间
        expiry_date = timezone_now() - timedelta(days=days)
        logger.debug(f"清理截止日期: {expiry_date}")
        
        session = get_db_session()
        try:
            # 查询过期的回收站项目
            expired_items = session.query(RecycleBin).filter(
                RecycleBin.deleted_at < expiry_date
            ).all()
            
            logger.debug(f"查询结果: 找到{len(expired_items)}个过期回收站项目")
            
            if not expired_items:
                logger.info("没有需要清理的回收站项目")
                logger.debug("没有找到需要清理的回收站项目，返回成功结果")
                return_data = {'success': True, 'deleted_count': 0}
                logger.debug(f"返回结果: {return_data}")
                return return_data
            
            # 删除过期回收站项目
            deleted_count = 0
            logger.debug(f"开始处理{len(expired_items)}个过期回收站项目")
            for item in expired_items:
                logger.debug(f"删除回收站项目: ID={item.id}, 类型={item.item_type}, 名称={item.original_name}")
                session.delete(item)
                deleted_count += 1
                logger.debug(f"已处理{deleted_count}/{len(expired_items)}个回收站项目")
            
            logger.debug(f"提交删除操作到数据库")
            session.commit()
            logger.debug(f"数据库提交成功")
            
            logger.info(f"清理完成，共删除{deleted_count}个回收站项目")
            return_data = {'success': True, 'deleted_count': deleted_count}
            logger.debug(f"返回清理结果: {return_data}")
            
            # 记录回收站清理成功的信息日志
            log_info(
                "scheduler_cleanup_recycle_items_success",
                {
                    "deleted_count": deleted_count,
                    "cleanup_days": days,
                    "execution_context": {
                        "function": "cleanup_recycle_items",
                        "module": "scheduler.tasks"
                    }
                }
            )
            
            # 记录系统事件日志
            log_system_event(
                level='INFO',
                module='scheduler',
                message=f"定时清理回收站成功，删除了{deleted_count}个过期项目",
                details=json.dumps({
                    "deleted_count": deleted_count,
                    "cleanup_days": days,
                    "expiry_date": expiry_date.isoformat(),
                    "execution_context": {
                        "function": "cleanup_recycle_items",
                        "module": "scheduler.tasks",
                        "operation": "cleanup_expired_recycle_items",
                        "cleanup_type": "batch_delete"
                    }
                }, ensure_ascii=False),
                action='CLEANUP_RECYCLE_ITEMS',
                resource_type='RECYCLE_ITEM'
            )
            
            return return_data
        finally:
            close_db_session()
            
    except Exception as e:
        error_msg = f"清理回收站项目失败: {str(e)}"
        logger.error(error_msg)
        logger.debug(f"清理回收站项目异常详情: {traceback.format_exc()}")
        
        # 记录详细的系统错误日志
        log_error(
            "scheduler_cleanup_recycle_items_failed",
            {
                "error_type": type(e).__name__,
                "error_message": str(e),
                "stack_trace": traceback.format_exc(),
                "execution_context": {
                    "function": "cleanup_recycle_items",
                    "module": "scheduler.tasks",
                    "cleanup_days": days
                }
            }
        )
        
        # 记录系统事件日志
        log_system_event(
            level='ERROR',
            module='scheduler',
            message=f"定时清理回收站失败: {str(e)}",
            details=json.dumps({
                "days": days,
                "error_type": type(e).__name__,
                "error_message": str(e),
                "stack_trace": traceback.format_exc(),
                "execution_context": {
                    "function": "cleanup_recycle_items",
                    "module": "scheduler.tasks",
                    "operation": "cleanup_expired_recycle_items",
                    "cleanup_type": "batch_delete"
                }
            }, ensure_ascii=False),
            action='CLEANUP_RECYCLE_ITEMS',
            resource_type='RECYCLE_ITEM'
        )
        
        return_data = {'success': False, 'error': error_msg}
        logger.debug(f"返回错误结果: {return_data}")
        return return_data
    finally:
        close_db_session()





@celery_app.task(name='reload_tasks')
def reload_tasks():
    """重新加载所有活跃任务
    
    Returns:
        加载结果字典
    """
    logger.debug("开始重新加载所有活跃任务")
    logger.info("重新加载所有活跃任务")
    
    # 使用Redis分布式锁防止重复执行
    import redis
    from config.config import get_config
    
    config = get_config()
    
    # 获取分布式锁
    import redis
    redis_client = redis.from_url(config.REDIS_URL, decode_responses=True)
    
    lock_key = "reload_tasks_lock"
    lock_timeout = 30  # 30秒超时
    
    # 尝试获取锁
    if not redis_client.set(lock_key, "locked", nx=True, ex=lock_timeout):
        logger.info("另一个reload_tasks任务正在执行，跳过本次执行")
        return {'success': True, 'result': {'skipped': True, 'reason': 'Another reload_tasks is running'}}
    
    try:
        logger.debug("获取到分布式锁，开始执行任务重新加载")
        logger.debug("导入TaskScheduler类")
        from services.scheduler.scheduler import TaskScheduler
        logger.debug("初始化TaskScheduler实例")
        scheduler = TaskScheduler()
        logger.debug("调用reload_all_tasks方法")
        result = scheduler.reload_all_tasks()
        logger.debug(f"reload_all_tasks方法返回结果: {result}")
        
        logger.info(f"任务重新加载完成: {result}")
        return_data = {'success': True, 'result': result}
        logger.debug(f"返回加载结果: {return_data}")
        
        # 记录任务重新加载成功的信息日志
        log_info(
            "scheduler_reload_tasks_success",
            f"任务重新加载成功，加载了{result.get('loaded_tasks', 0)}个任务",
            details=json.dumps({
                "result": result,
                "execution_context": {
                    "function": "reload_tasks",
                    "module": "scheduler.tasks",
                    "lock_key": "reload_tasks_lock"
                }
            }, ensure_ascii=False)
        )
        
        return return_data
    except Exception as e:
        error_msg = f"重新加载任务失败: {str(e)}"
        logger.error(error_msg)
        logger.debug(f"重新加载任务异常详情: {traceback.format_exc()}")
        
        # 记录详细的系统错误日志
        log_error(
            "scheduler_reload_tasks_failed",
            {
                "error_type": type(e).__name__,
                "error_message": str(e),
                "stack_trace": traceback.format_exc(),
                "execution_context": {
                    "function": "reload_tasks",
                    "module": "scheduler.tasks",
                    "lock_key": "reload_tasks_lock"
                }
            }
        )
        
        return_data = {'success': False, 'error': error_msg}
        logger.debug(f"返回错误结果: {return_data}")
        return return_data
    finally:
        # 释放锁
        redis_client.delete(lock_key)
        logger.debug("已释放分布式锁")


@celery_app.task(name='cleanup_executions')
def cleanup_executions():
    """清理过期的执行记录
    
    Returns:
        清理结果字典
    """
    logger.debug("开始执行清理过期的执行记录")
    logger.info("开始清理过期的执行记录")
    
    try:
        # 获取已完成或失败的执行记录，且时间超过30天
        from datetime import timedelta
        thirty_days_ago = timezone_now() - timedelta(days=30)
        logger.debug(f"查询30天前({thirty_days_ago})的已完成或失败的执行记录")
        
        session = get_db_session()
        try:
            
            expired_executions = TaskExecution.query.filter(
                TaskExecution.status.in_([TaskStatus.COMPLETED.value, TaskStatus.FAILED.value]),
                TaskExecution.finished_at <= thirty_days_ago
            ).all()
            
            logger.debug(f"查询结果: 找到{len(expired_executions)}个过期执行记录")
            
            if not expired_executions:
                logger.info("没有需要清理的执行记录")
                logger.debug("没有找到需要清理的执行记录，返回成功结果")
                return_data = {'success': True, 'deleted_count': 0}
                logger.debug(f"返回结果: {return_data}")
                return return_data
            
            # 删除过期执行记录
            deleted_count = 0
            logger.debug(f"开始处理{len(expired_executions)}个过期执行记录")
            for execution in expired_executions:
                logger.debug(f"删除执行记录: ID={execution.id}, 任务ID={execution.task_id}, 执行ID={execution.execution_id}")
                db.session.delete(execution)
                deleted_count += 1
                logger.debug(f"已处理{deleted_count}/{len(expired_executions)}个执行记录")
            
            logger.debug(f"提交删除操作到数据库")
            db.session.commit()
            logger.debug(f"数据库提交成功")
            
            logger.info(f"清理完成，共删除{deleted_count}个执行记录")
            return_data = {'success': True, 'deleted_count': deleted_count}
            logger.debug(f"返回清理结果: {return_data}")
            
            # 记录执行记录清理成功的信息日志
            log_info(
                "scheduler_cleanup_executions_success",
                {
                    "deleted_count": deleted_count,
                    "cleanup_days": 30,
                    "execution_context": {
                        "function": "cleanup_executions",
                        "module": "scheduler.tasks"
                    }
                }
            )
            
            return return_data
        finally:
            close_db_session()
            
    except Exception as e:
        error_msg = f"清理执行记录失败: {str(e)}"
        logger.error(error_msg)
        logger.debug(f"清理执行记录异常详情: {traceback.format_exc()}")
        
        # 记录详细的系统错误日志
        log_error(
            "scheduler_cleanup_executions_failed",
            {
                "error_type": type(e).__name__,
                "error_message": str(e),
                "stack_trace": traceback.format_exc(),
                "execution_context": {
                    "function": "cleanup_executions",
                    "module": "scheduler.tasks",
                    "cleanup_days": 30
                }
            }
        )
        
        return_data = {'success': False, 'error': error_msg}
        logger.debug(f"返回错误结果: {return_data}")
        return return_data


@celery_app.task(name='cleanup_tasks')
def cleanup_tasks():
    """清理已删除的任务
    
    Returns:
        清理结果字典
    """
    logger.debug("开始执行清理已删除的任务")
    logger.info("开始清理已删除的任务")
    
    try:
        logger.debug("获取应用上下文")
        with db.app.app_context():
            # 获取已删除的任务
            logger.debug(f"查询状态为{TaskStatus.DELETED.value}的已删除任务")
            deleted_tasks = Task.query.filter_by(status=TaskStatus.DELETED.value).all()
            logger.debug(f"查询结果: 找到{len(deleted_tasks)}个已删除任务")
            
            if not deleted_tasks:
                logger.info("没有需要清理的任务")
                logger.debug("没有找到需要清理的任务，返回成功结果")
                return_data = {'success': True, 'deleted_count': 0}
                logger.debug(f"返回结果: {return_data}")
                return return_data
            
            # 删除任务及其执行记录
            deleted_count = 0
            logger.debug(f"开始处理{len(deleted_tasks)}个已删除任务")
            for task in deleted_tasks:
                # 删除任务的执行记录
                logger.debug(f"删除任务ID为{task.id}的执行记录")
                execution_count = TaskExecution.query.filter_by(task_id=task.id).count()
                logger.debug(f"找到{execution_count}条执行记录需要删除")
                TaskExecution.query.filter_by(task_id=task.id).delete()
                
                # 删除任务
                logger.debug(f"删除任务: ID={task.id}, 名称={task.name if hasattr(task, 'name') else '未知'}")
                db.session.delete(task)
                deleted_count += 1
                logger.debug(f"已处理{deleted_count}/{len(deleted_tasks)}个任务")
            
            logger.debug(f"提交删除操作到数据库")
            db.session.commit()
            logger.debug(f"数据库提交成功")
            
            logger.info(f"清理完成，共删除{deleted_count}个任务")
            return_data = {'success': True, 'deleted_count': deleted_count}
            logger.debug(f"返回清理结果: {return_data}")
            
            # 记录任务清理成功的信息日志
            log_info(
                "scheduler_cleanup_tasks_success",
                {
                    "deleted_count": deleted_count,
                    "task_status": "DELETED",
                    "execution_context": {
                        "function": "cleanup_tasks",
                        "module": "scheduler.tasks"
                    }
                }
            )
            
            return return_data
            
    except Exception as e:
        error_msg = f"清理任务失败: {str(e)}"
        logger.error(error_msg)
        logger.debug(f"清理任务异常详情: {traceback.format_exc()}")
        
        # 记录详细的系统错误日志
        log_error(
            "scheduler_cleanup_tasks_failed",
            {
                "error_type": type(e).__name__,
                "error_message": str(e),
                "stack_trace": traceback.format_exc(),
                "execution_context": {
                    "function": "cleanup_tasks",
                    "module": "scheduler.tasks",
                    "task_status": "DELETED"
                }
            }
        )
        
        return_data = {'success': False, 'error': error_msg}
        logger.debug(f"返回错误结果: {return_data}")
        return return_data